package com.finalterm.order.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.finalterm.common.constant.Constants;
import com.finalterm.common.exception.BusinessException;
import com.finalterm.common.result.Result;
import com.finalterm.order.dto.OrderCreateDTO;
import com.finalterm.order.entity.Order;
import com.finalterm.order.feign.ProductServiceClient;
import com.finalterm.order.feign.UserServiceClient;
import com.finalterm.order.mapper.OrderMapper;
import com.finalterm.order.service.CompensationTaskService;
import com.finalterm.order.service.OrderService;
import com.finalterm.order.service.StockConfirmService;
import com.finalterm.order.vo.OrderVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 订单服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final OrderMapper orderMapper;
    private final UserServiceClient userServiceClient;
    private final ProductServiceClient productServiceClient;
    private final CompensationTaskService compensationTaskService;
    private final StockConfirmService stockConfirmService;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderVO createOrder(Long userId, OrderCreateDTO createDTO) {
        // 1. 验证用户有效性
        Result<Boolean> userResult = userServiceClient.validateUser(userId);
        if (userResult.getCode() != 200 || userResult.getData() == null || !userResult.getData()) {
            throw new BusinessException("用户验证失败");
        }
        
        // 2. 获取商品信息
        Result<Object> productResult = productServiceClient.getProductDetail(createDTO.getProductId());
        if (productResult.getCode() != 200 || productResult.getData() == null) {
            throw new BusinessException("商品信息获取失败");
        }
        
        JSONObject productData = JSON.parseObject(JSON.toJSONString(productResult.getData()));
        String productName = productData.getString("name");
        BigDecimal productPrice = productData.getBigDecimal("price");
        Integer stock = productData.getInteger("stock");
        
        // 3. 检查库存
        if (stock < createDTO.getQuantity()) {
            throw new BusinessException("库存不足");
        }
        
        // 4. 生成订单号
        String orderNo = generateOrderNo();
        
        // 5. 扣减库存
        Map<String, Object> deductDTO = new HashMap<>();
        deductDTO.put("productId", createDTO.getProductId());
        deductDTO.put("quantity", createDTO.getQuantity());
        deductDTO.put("orderId", orderNo);
        
        Result<Boolean> deductResult = productServiceClient.deductStock(deductDTO);
        if (deductResult.getCode() != 200 || deductResult.getData() == null || !deductResult.getData()) {
            throw new BusinessException("库存扣减失败");
        }
        
        // 6. 创建订单
        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setUserId(userId);
        order.setProductId(createDTO.getProductId());
        order.setProductName(productName);
        order.setProductPrice(productPrice);
        order.setQuantity(createDTO.getQuantity());
        order.setTotalAmount(productPrice.multiply(new BigDecimal(createDTO.getQuantity())));
        order.setStatus(Constants.ORDER_STATUS_PENDING);
        order.setAddress(createDTO.getAddress());
        order.setPhone(createDTO.getPhone());
        order.setRemark(createDTO.getRemark());
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        
        orderMapper.insert(order);
        
        // 7. 转换为VO返回
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);
        
        log.info("订单创建成功，订单号：{}", orderNo);
        return orderVO;
    }
    
    @Override
    public OrderVO getOrderById(Long orderId) {
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在");
        }
        
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);
        return orderVO;
    }
    
    @Override
    public OrderVO getOrderByOrderNo(String orderNo) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(wrapper);
        
        if (order == null) {
            throw new BusinessException("订单不存在");
        }
        
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);
        return orderVO;
    }
    
    @Override
    public Page<OrderVO> getUserOrders(Long userId, int page, int size) {
        Page<Order> orderPage = new Page<>(page, size);
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getUserId, userId);
        wrapper.orderByDesc(Order::getCreateTime);
        
        Page<Order> result = orderMapper.selectPage(orderPage, wrapper);
        
        // 转换为VO
        Page<OrderVO> voPage = new Page<>();
        BeanUtils.copyProperties(result, voPage);
        
        List<OrderVO> voList = result.getRecords().stream().map(order -> {
            OrderVO vo = new OrderVO();
            BeanUtils.copyProperties(order, vo);
            return vo;
        }).collect(Collectors.toList());
        
        voPage.setRecords(voList);
        return voPage;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderStatus(String orderNo, String status) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(wrapper);

        if (order == null) {
            throw new BusinessException("订单不存在");
        }

        order.setStatus(status);
        order.setUpdateTime(LocalDateTime.now());

        if (Constants.ORDER_STATUS_PAID.equals(status)) {
            order.setPayTime(LocalDateTime.now());
        }

        int affected = orderMapper.updateById(order);

        log.info("订单状态更新成功，订单号：{}，状态：{}", orderNo, status);

        // 订单状态更新成功后，异步确认库存扣减，保证最终一致性
        if (affected > 0) {
            try {
                stockConfirmService.confirmStockDeductionAsync(
                    orderNo, order.getProductId(), order.getQuantity(), status);
                log.info("已发起异步库存确认，订单号：{}", orderNo);
            } catch (Exception e) {
                log.error("发起异步库存确认失败，订单号：{}，异常：{}", orderNo, e.getMessage(), e);
                // 异步调用失败不影响订单状态更新的结果
            }
        }

        return affected > 0;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelOrder(String orderNo) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getOrderNo, orderNo);
        Order order = orderMapper.selectOne(wrapper);
        
        if (order == null) {
            throw new BusinessException("订单不存在");
        }
        
        if (!Constants.ORDER_STATUS_PENDING.equals(order.getStatus())) {
            throw new BusinessException("只能取消待支付订单");
        }
        
        // 恢复库存
        Result<Boolean> recoverResult = productServiceClient.recoverStock(
                order.getProductId(), order.getQuantity(), order.getOrderNo());

        if (recoverResult.getCode() != 200 || recoverResult.getData() == null || !recoverResult.getData()) {
            log.warn("库存恢复失败，创建补偿任务，订单号：{}", orderNo);
            // 创建补偿任务
            compensationTaskService.createStockRecoverTask(order.getOrderNo(), order.getProductId(), order.getQuantity());
        }
        
        // 更新订单状态
        order.setStatus(Constants.ORDER_STATUS_CANCELLED);
        order.setUpdateTime(LocalDateTime.now());
        
        int affected = orderMapper.updateById(order);
        
        log.info("订单取消成功，订单号：{}", orderNo);
        return affected > 0;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleTimeoutOrders() {
        // 查询30分钟前创建的未支付订单
        LocalDateTime timeoutTime = LocalDateTime.now().minusMinutes(30);
        List<Order> timeoutOrders = orderMapper.selectTimeoutOrders(timeoutTime);
        
        for (Order order : timeoutOrders) {
            try {
                // 恢复库存
                Result<Boolean> recoverResult = productServiceClient.recoverStock(
                        order.getProductId(), order.getQuantity(), order.getOrderNo());

                if (recoverResult.getCode() != 200 || recoverResult.getData() == null || !recoverResult.getData()) {
                    log.warn("超时订单库存恢复失败，创建补偿任务，订单号：{}", order.getOrderNo());
                    // 创建补偿任务
                    compensationTaskService.createStockRecoverTask(order.getOrderNo(), order.getProductId(), order.getQuantity());
                    // 继续处理订单状态更新，即使库存恢复失败
                }
                
                // 更新订单状态为超时
                order.setStatus(Constants.ORDER_STATUS_TIMEOUT);
                order.setUpdateTime(LocalDateTime.now());
                orderMapper.updateById(order);
                
                log.info("超时订单处理成功，订单号：{}", order.getOrderNo());
            } catch (Exception e) {
                log.error("处理超时订单失败，订单号：{}，错误：{}", order.getOrderNo(), e.getMessage());
            }
        }
    }
    
    /**
     * 生成订单号
     */
    private String generateOrderNo() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String random = String.valueOf((int) (Math.random() * 10000));
        return "ORD" + timestamp + String.format("%04d", Integer.parseInt(random));
    }
}
